package com.qy.changemachine.util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.RecoverySystem;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;

import com.qy.changemachine.api.DownloadUtil;
import com.qy.changemachine.callBack.ActionCallBack;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class Utils {
    private static final String TAG = "Utils";
    private final Context mContext;
    private int mSessionId = -1;
    private final PackageInstaller.SessionCallback mSessionCallback;
    private final ActionCallBack actionCallBack;
    public String apkName = "";

    public Utils(Context context, ActionCallBack callBack) {
        mContext = context;
        actionCallBack = callBack;
        mSessionCallback = new InstallSessionCallback();
        context.getPackageManager().getPackageInstaller().registerSessionCallback(mSessionCallback);
    }

    private CompletableFuture<Boolean> installFuture;

    public void installAppSync(String apkFilePath) {
        installApp(apkFilePath); // 调用异步安装方法
        installFuture = new CompletableFuture<>();
        try {
            // 等待安装完成
            boolean result = installFuture.get();
            Log.d(TAG, "安装结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    public void installApp(String apkFilePath) {
        Log.d(TAG, "installApp()------->" + apkFilePath);
        apkName = apkFilePath;
        File apkFile = new File(apkFilePath);
        Log.d(TAG, "文件是否可读: " + apkFile.canRead());
        if (!apkFile.exists()) {
            Log.d(TAG, "文件不存在");
            showToast("安装文件不存在");
            return;
        }

        PackageInfo packageInfo = mContext.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
        if (packageInfo != null) {
            String packageName = packageInfo.packageName;
            int versionCode = packageInfo.versionCode;
            String versionName = packageInfo.versionName;
            Log.d(TAG, "packageName=" + packageName + ", versionCode=" + versionCode + ", versionName=" + versionName);
        } else {
            Log.d(TAG, "无法解析 APK 文件");
            return;
        }

        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        Log.d(TAG, "apkFile length" + apkFile.length());
        sessionParams.setSize(apkFile.length());

        try {
            mSessionId = packageInstaller.createSession(sessionParams);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d(TAG, "sessionId---->" + mSessionId);
        if (mSessionId != -1) {
            boolean copySuccess = onTransfesApkFile(apkFilePath);
            Log.d(TAG, "copySuccess---->" + copySuccess);
            if (copySuccess) {
                execInstallAPP();
            }
        }
    }

    /**
     * 通过文件流传输apk
     *
     * @param apkFilePath
     * @return
     */
    private boolean onTransfesApkFile(String apkFilePath) {
        Log.d(TAG, "---------->onTransfesApkFile()<---------------------");
        InputStream in = null;
        OutputStream out = null;
        PackageInstaller.Session session = null;
        boolean success = false;
        try {
            File apkFile = new File(apkFilePath);
            session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
            out = session.openWrite("base.apk", 0, apkFile.length());
            in = new FileInputStream(apkFile);
            int total = 0, c;
            byte[] buffer = new byte[1024 * 1024];
            while ((c = in.read(buffer)) != -1) {
                total += c;
                out.write(buffer, 0, c);
            }
            session.fsync(out);
            Log.d(TAG, "streamed " + total + " bytes");
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != session) {
                session.close();
            }
            try {
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 执行安装并通知安装结果
     */
    private void execInstallAPP() {
        Log.d(TAG, "--------------------->execInstallAPP()<------------------");
        PackageInstaller.Session session = null;
        try {
            session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);

            // 创建 Intent 和 PendingIntent
            Intent intent = new Intent(mContext, InstallResultReceiver.class);
            intent.setAction("ACTION_INSTALL_RESULT");
            // 设置自定义权限
            intent.setPackage(mContext.getPackageName()); // 确保广播只发送给自己的应用
            // 设置 PendingIntent 的标志位，考虑 API 版本
            int flags = PendingIntent.FLAG_UPDATE_CURRENT;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                flags |= PendingIntent.FLAG_IMMUTABLE; // 如果不需要 Pending Intent 可变，则使用
                // 或者如果确实需要可变的 Pending Intent，则使用下面这一行代替上面一行：
                // flags |= PendingIntent.FLAG_MUTABLE;
            }

            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 1, intent, flags);

            session.commit(pendingIntent.getIntentSender());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != session) {
                session.close();
            }
        }
    }

    // 卸载app
    public void uninstall(String packageName) {
        Intent broadcastIntent = new Intent(mContext, InstallResultReceiver.class);

        // 设置 PendingIntent 的标志位，考虑 API 版本
        int flags = PendingIntent.FLAG_UPDATE_CURRENT;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            flags |= PendingIntent.FLAG_IMMUTABLE; // 如果不需要 Pending Intent 可变，则使用 FLAG_IMMUTABLE
            // 或者如果确实需要可变的 Pending Intent，则使用下面这一行代替上面一行：
            // flags |= PendingIntent.FLAG_MUTABLE;
        }

        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 1, broadcastIntent, flags);

        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        packageInstaller.uninstall(packageName, pendingIntent.getIntentSender());
    }


    // 传入 Context，适用于非 Activity 类
    public void copyFileToSDCard(int id, String name) {
        // 获取 SD 卡路径（适配不同版本的存储权限）
        File sdCard = new File(Contants.DATA_PATH);
        File dir = new File(sdCard, "");  // 将文件复制到 Download 文件夹
        if (!dir.exists()) {
            dir.mkdirs();  // 创建目录
        }

        // 定义目标文件 "qq.apk"
        File outFile = new File(Contants.DATA_PATH, name);

        // 从 APK 的 res/raw 目录读取文件 R.raw.qq
        try (InputStream in = mContext.getResources().openRawResource(id); // 这里假设文件名为 "qq.apk" 存放在 res/raw 目录下
             OutputStream out = new FileOutputStream(outFile)) {

            // 复制文件
            byte[] buffer = new byte[1024];
            int length;
            while ((length = in.read(buffer)) > 0) {
                out.write(buffer, 0, length);
            }
            // 成功后显示提示
            showToast("文件已复制到 SD 卡！");
            if (actionCallBack != null) {
                actionCallBack.copyFile2SdcardSuccess(name);
            }
        } catch (IOException e) {
            if (actionCallBack != null) {
                actionCallBack.copyFile2SdcardFail(name + " exception:" + e.getMessage());
            }
            Log.d(TAG, "复制文件失败" + e.getMessage());
            showToast("复制文件失败！");
        }
    }

    public void setAccessibility(Context context) {
        Settings.Secure.putString(context.getApplicationContext().getContentResolver(),
                "enabled_accessibility_services",
                "com.android.tools/com.stardust.autojs.core.accessibility.AccessibilityService");
    }

    public void openNtp(Context context) {
        Settings.Global.putString(context.getApplicationContext().getContentResolver(), "ntp_server", "cn.pool.ntp.org");
        Settings.Global.putInt(context.getApplicationContext().getContentResolver(), "auto_time", 1);
        Settings.Global.putInt(context.getApplicationContext().getContentResolver(), "auto_time_zone", 0);
    }

    @SuppressLint("MissingPermission")
    public void closeBluetooth() {
        BluetoothAdapter.getDefaultAdapter().disable();
    }

    public boolean setDefaultDns() {
        for (int i = 0; i < Contants.data.length; i++) {
            String ip = Contants.data[i][0];
            String domain = Contants.data[i][1];
            boolean z = setDNSResolve(domain, ip, i != 0);
            if (!z) {
                return false;
            }
        }
        return true;
    }

    public void factoryReset(Context context) {
        Intent intent = new Intent("android.intent.action.FACTORY_RESET");
        intent.setPackage("android");
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra("android.intent.extra.REASON", "MainClearConfirm");
        //是否格式化sdcard
        intent.putExtra("android.intent.extra.WIPE_EXTERNAL_STORAGE", true);
        //是否格式化eSIM数据
        intent.putExtra("com.android.internal.intent.extra.WIPE_ESIMS", true);
        context.sendBroadcast(intent);
    }

    /**
     * 读取json文件中得字符串
     ***/
    public String readJsonFileToString(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            Log.d(TAG, "====>readJsonFileToString 文件不存在");
            return null; // 文件不存在
        }

        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] data = new byte[(int) file.length()];
            fis.read(data);
            return new String(data, StandardCharsets.UTF_8); // 将字节数组转换为字符串
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将字符串压缩为 Gzip 格式的字节数组
     */
    public byte[] compressString(String input) {
        try (
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                GZIPOutputStream gzip = new GZIPOutputStream(bos);
        ) {
            gzip.write(input.getBytes(StandardCharsets.UTF_8));
            gzip.finish(); // 确保所有数据写入
            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将 Gzip 格式的字节数组解压缩为字符串
     */
    public String decompressToString(byte[] compressedData) {
        try (
                ByteArrayInputStream bis = new ByteArrayInputStream(compressedData);
                GZIPInputStream gzip = new GZIPInputStream(bis);
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = gzip.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            return bos.toString(StandardCharsets.UTF_8.name());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public String getImei() {
        String imei = null;
        TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        final int maxRetries = 5; // 设置最大重试次数

        for (int attempt = 0; attempt < maxRetries; attempt++) {
            if (telephonyManager != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    // Android 10 及以上获取 IMEI
                    imei = telephonyManager.getImei(); // 获取默认 SIM 卡的 IMEI
                    // 如果是双卡设备，可以使用 getImei(int slotIndex) 获取指定 SIM 卡的 IMEI
                    // imei = telephonyManager.getImei(0); // 获取第一个 SIM 卡的 IMEI
                    // imei = telephonyManager.getImei(1); // 获取第二个 SIM 卡的 IMEI
                } else {
                    // Android 9 及以下获取 IMEI
                    imei = telephonyManager.getDeviceId(); // 获取默认 SIM 卡的 IMEI
                }
            }
            if (imei != null) {
                break; // 成功获取到 IMEI，退出循环
            } else {
                try {
                    Thread.sleep(1000); // 每次尝试之间等待1秒，避免过于频繁地请求
                    LogUtil.INSTANCE.d(TAG, "====>:get iemi is null sleep 1s try again");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        if (imei == null) {
            // 如果多次尝试后仍未获取到 IMEI，则使用 IP 地址作为替代
            imei = NetworkUtils.getIpAddress();
        }

        Log.d(TAG, "------------->imei:" + imei);
        return imei;
    }


    public void execAutoJs(Context context) {
        try {
            // 创建一个显式的Intent
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.android.tools", "org.autojs.autojs.LogRunActivity"));
            // 如果需要传递额外的数据，可以在这里添加
            ShellUtils.CommandResult result = ShellUtils.execCommand("chmod 777 " + Contants.AUTO_JS_PATH, true);
            Log.d(TAG, "downLoadSuccess------>ShellUtils.execCommand:" + result);
            intent.putExtra("key", Contants.AUTO_JS_PATH);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
            // 启动Activity
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            // 处理找不到Activity的情况
            Log.e("MyApp", "Failed to start LogRunActivity", e);
            showToast("无法启动 LogRunActivity，请确保 org.autojs.autojs 应用已安装");

        }
    }

    private CompletableFuture<Boolean> downFuture;

    public void downLoad(String url, String pathName, Boolean isAsync) {
        LogUtil.INSTANCE.d(TAG, "downLoad------>url0:" + url + "==>pathName:" + pathName);
        DownloadUtil.getInstance().download(url, pathName, new DownloadUtil.OnDownloadListener() {
            @Override
            public void onDownloadSuccess(String path) {
                // 下载成功后的操作
                LogUtil.INSTANCE.d(TAG, "downLoad------>url2 Download Success!:init downFuture clock");
                showToast("Download Success!" + pathName);
                if (actionCallBack != null) {
                    actionCallBack.downLoadSuccess(pathName);
                }
                if (isAsync && downFuture != null) {
                    downFuture.complete(true);
                }
            }

            @Override
            public void onDownloading(int progress) {
            }

            @Override
            public void onDownloadFailed(String msg) {
                // 处理下载失败的情况
                LogUtil.INSTANCE.d(TAG, "downLoad------>url2 Download Failed!:init downFuture clock");
                showToast("Download Failed!" + pathName);
                if (actionCallBack != null) {
                    actionCallBack.downLoadFail(pathName + "msg:" + msg);
                }
                if (isAsync && downFuture != null) {
                    downFuture.complete(false);
                }
            }
        });
        LogUtil.INSTANCE.d(TAG, "downLoad------>url1:init downFuture clock");
        downFuture = new CompletableFuture<>();
        try {
            if (isAsync) {
                downFuture.get();
            }
        } catch (Exception e) {
            Log.d(TAG, url + " downFuture.get() exception：" + e.getMessage());
        }
    }


    public void showToast(String message) {
        try {
            if (mContext instanceof Activity) {
                ((Activity) mContext).runOnUiThread(() -> {
                    Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
                });
            } else {
                // 如果不是 Activity，使用 Handler
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(() -> {
                    Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
                });
            }
        } catch (Exception e) {
            Log.d(TAG, "showToast exception：" + e.getMessage());
        }

    }


    class InstallSessionCallback extends PackageInstaller.SessionCallback {
        @Override
        public void onCreated(int sessionId) {
            // empty
            Log.d(TAG, "onCreated()" + sessionId);
        }

        @Override
        public void onBadgingChanged(int sessionId) {
            // empty
            Log.d(TAG, "onBadgingChanged()" + sessionId + "active");
        }

        @Override
        public void onActiveChanged(int sessionId, boolean active) {
            // empty
            Log.d(TAG, "onActiveChanged()" + sessionId + "active" + active);
        }

        @Override
        public void onProgressChanged(int sessionId, float progress) {
            Log.d(TAG, "onProgressChanged()" + sessionId);
            if (sessionId == mSessionId) {
                int progres = (int) (Integer.MAX_VALUE * progress);
                Log.d(TAG, "onProgressChanged" + progres);
            }
        }

        @Override
        public void onFinished(int sessionId, boolean success) {
            // empty, finish is handled by InstallResultReceiver
            Log.d(TAG, "onFinished()" + sessionId + "success" + success);
            if (mSessionId == sessionId) {
                if (success) {
                    Log.d(TAG, apkName + "onFinished() 安装成功");
                    showToast(apkName + "onFinished() 安装成功");
                    if (actionCallBack != null) {
                        actionCallBack.installSuccess(apkName);
                    }
                } else {
                    Log.d(TAG, "onFinished() 安装失败");
                    showToast("onFinished() 安装失败");
                    if (actionCallBack != null) {
                        actionCallBack.installFail(apkName);
                    }
                }

            }
            // 释放资源
            mSessionId = -1; // 重置 Session ID
            // 完成 CompletableFuture
            if (installFuture != null) {
                installFuture.complete(success);
            }
        }
    }

    //修改eth手机 ip
    public void changIPInfo() {
        EthernetConfigurator configurator = new EthernetConfigurator(mContext);
//            // 更新完整的网络配置
        String interfaceName = "eth0"; // 以太网接口名称
        String ipAddress = "192.168.1.203";
        String gateway = "192.168.1.250";
        String dns = "8.8.8.8";
        String subnetMask = "255.255.255.0";
        configurator.configureEthernet(interfaceName, ipAddress, gateway, dns, subnetMask);

//            // 仅更新网关
//            String newGateway = "192.168.1.250"; // 新的网关地址
//            configurator.updateGateway(interfaceName, newGateway);
    }


    /**
     * 检查应用是否已安装
     *
     * @param packageName 应用的包名
     * @return true 表示已安装，false 表示未安装
     */
    public boolean isAppInstalled(String packageName) {
        try {
            // 获取 PackageManager
            PackageManager pm = mContext.getPackageManager();
            // 尝试获取应用信息，如果未安装会抛出异常
            pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
            return true; // 应用已安装
        } catch (PackageManager.NameNotFoundException e) {
            // 应用未安装
            return false;
        }
    }

    public boolean otaUpdate(Context context, String path) {
        try {
            Intent intent = new Intent();
            intent.putExtra("OTA_PATH", path);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClassName(
                    "org.lineageos.updater",
                    "org.lineageos.updater.UpdatesActivity"
            );
            context.startActivity(intent);
            return true;
        } catch (Exception e) {
            Log.d(TAG, "OTAupdate exception:" + e.getMessage());
            return false;
        }
    }

    public boolean startApp(Context context, String packageName,
                            String mainActivity, String key, String value) {
        try {
            Intent intent = new Intent();
            intent.putExtra(key, value);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setClassName(
                    packageName,
                    mainActivity
            );
            context.startActivity(intent);
            return true;
        } catch (Exception e) {
            Log.d(TAG, "startApp exception:" + e.getMessage());
            return false;
        }
    }

    @SuppressLint("MissingPermission")
    public boolean otaUpdate(Context context, File update) {
        try {
            ShellUtils.execCommand("chmod 777 " + Contants.OTA_DOWNLOAD_PATH, true);
            ShellUtils.execCommand("chown system:system " + Contants.OTA_DOWNLOAD_PATH, true);
            RecoverySystem.installPackage(context, update);
            return true;
        } catch (Exception e) {
            Log.d(TAG, "OTAupdate exception:" + e.getMessage());
            return false;
        }
    }

    public boolean verifyPackageInstallPackage(File update) {
        try {
            // 校验更新包
            ShellUtils.execCommand("chmod 777 " + Contants.OTA_DOWNLOAD_PATH, true);
            ShellUtils.execCommand("chown system:system " + Contants.OTA_DOWNLOAD_PATH, true);
            RecoverySystem.verifyPackage(update, null, null);
            Log.d(TAG, "Installation of update package initiated successfully.");
            return true;
        } catch (IOException e) {
            // 增强错误信息
            Log.e(TAG, "Could not install update from path: " + update.getAbsolutePath() + ":" + e.getMessage());
            return false;
        } catch (Exception e) {
            // 捕获其他未预见的异常
            Log.e(TAG, "Unexpected error during update verification: " + e.getMessage());
            return false;
        }
    }


    @SuppressLint("MissingPermission")
    public void setSystemTime(Context context, long timestamp) {
        Log.e(TAG, "setSystemTime: " + timestamp);
        if (timestamp <= 0) {
            return;
        }
        // 确保时间戳是毫秒级
        if (timestamp < 1000000000000L) { // 可能是秒级时间戳
            timestamp *= 1000;
        }
        System.setProperty("user.timezone", "Asia/Shanghai");
        SystemPropertiesReflector.set("persist.sys.timezone", "Asia/Shanghai");
        TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
        Calendar calendar = Calendar.getInstance(timeZone);
        calendar.setTimeInMillis(timestamp);

        try {
            // 获取 AlarmManager 实例
            AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            if (alarmManager != null) {
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                    // 设置系统时间
                    alarmManager.setTime(timestamp);
                    // 打印日志，按上海时区显示
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    sdf.setTimeZone(timeZone);
                    Log.e(TAG, "System time set to: " + sdf.format(calendar.getTime()));
                }
            } else {
                Log.e(TAG, "Failed to get AlarmManager service.");
            }
        } catch (Exception e) {
            Log.e(TAG, "Failed to set system time: " + e.getMessage());
        }
    }

    public boolean setDNSResolve(String dns, String ip, boolean append) {
        try {
            if (append) {
                //追加规则
                String cmd = String.format("echo -e %s\t%s >> /system/etc/hosts", ip, dns);
                ShellUtils.CommandResult result = ShellUtils.execCommand(cmd, true);
                LogUtil.INSTANCE.d(TAG, "setDNSResolve: " + cmd + " result:" + result);
                return result.result == 0;
            } else {
                //覆盖规则
                String cmd = String.format("echo -e %s\t%s> /system/etc/hosts", ip, dns);
                ShellUtils.CommandResult result = ShellUtils.execCommand(cmd, true);
                LogUtil.INSTANCE.d(TAG, "setDNSResolve: " + cmd + " result:" + result);
                return result.result == 0;
            }
        } catch (Exception e) {
            LogUtil.INSTANCE.d(TAG, "Failed to set system time: " + e.getMessage());
            return false;
        }

    }


}